import com.puppycrawl.tools.checkstyle.api.*;
import java.util.Map;
import java.util.Set;
import java.util.List;
/** This checkstyle custom-check looks for comments before
 *    each logic block 
 *   @author jdalbey
 *   @version 0.2    2013.11.2   for checkstyle 5.6
 */   
public class LogicCommentCheck extends Check
{
    private FileContents contents;
    private Set comments_c;
    private Set comments_cpp;

    /** Default constructor */
    public LogicCommentCheck()
    {
    }

    /** Returns the default token a check is interested in. 
     *  Only used if the configuration for a check does not define the tokens.
     *  @return int[] of default tokens
     */
    public int[] getDefaultTokens()
    {
        return (new int[] {
            TokenTypes.LITERAL_FOR,
            TokenTypes.LITERAL_WHILE,
            TokenTypes.LITERAL_DO,
            TokenTypes.LITERAL_SWITCH,
            TokenTypes.LITERAL_IF
        });
        //  91, 84, 85, 89, 83
    }

    /** Initialization for start of parsing.  
     *  Get the set of comments.
     *  @param detailast is the AST detail
     */
    public void beginTree(DetailAST detailast)
    {
        contents = getFileContents();
        comments_c = contents.getCComments().keySet();
        comments_cpp = contents.getCppComments().keySet();
    }
    /** Visit a token in the AST.  Here's where we do the real work
     *  of the custom check.  
     *  @param detailast is the AST detail
     */
    public void visitToken(DetailAST detailast)
    {
        // get which line we're on
        int lineNum = detailast.getLineNo();
        // See if the previous line is a comment, either c-style or cpp-style
        boolean isComment = contents.lineIsComment(lineNum - 1)
                          || comments_cpp.contains(Integer.valueOf(lineNum - 1));
        // if we failed to find one
        if ( !isComment )
        {
            /* Check for a c-style multi-line comment 
               that ends on the previous line. */
            for (List<TextBlock> comments : contents.getCComments().values())
            {
                /* Examine each comment */
                for (TextBlock comment : comments)
                {
                    // Does this comment end on the previous line?
                    if (comment.getEndLineNo() == (lineNum-1) )
                    {
                        isComment = true;
                    }
                }
            }   
        }
        /* See if a comment is present
           on several lines. */
        if (!isComment)
        {
            log(detailast.getLineNo(), "Logic structure must be preceded by a comment.");
        }    
    }

}
